#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include<memory>
#include<functional>
#include "log.hpp"
#include "addr.hpp"
using namespace std;
const int delfd = -1;

using func_t=function<string(string,inetaddr)>;
// consolestrategy;  不允许全局直接使用操作；只允许定义声明等等

class udpserver
{
public:
    // udpserver(string ip, uint16_t port) : _ip(ip), _port(port),
    //                                       _isrunning(0), _socketfd(delfd) {}

   //这里服务器不能绑死否则只能接受指定的主机发来的信息了
  //udpserver( uint16_t port) :  _port(port),  _isrunning(0), _socketfd(delfd) {}
  udpserver( uint16_t port,func_t func) :  _port(port),  _isrunning(0), _socketfd(delfd),_func(func) {}


    void init()
    {
        // 1`创建套接字：
        _socketfd = socket(AF_INET, SOCK_DGRAM, 0); // 网络通信/用户数据报;返回文件描述符
        if (_socketfd < 0)
            use_log(loglevel::DEBUG) << "socket failure!";
        use_log(loglevel::DEBUG) << "socket success!";
        // 2`socket绑定信息：

        sockaddr_in local;
        // char             sin_zero[8];填充字节，使 sockaddr_in 和 sockaddr 长度相同
        //套接字结构体初始化：
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;//网络通信
        local.sin_port = htons(_port); // 把对应的16位转化成网络序列
        // 内置的把string转化成大端类型的网络序列；也可手动操作（来回转化比较麻烦系统直接提供）
        // ntohs()网络序列转回本地
       //. local.sin_addr.s_addr = inet_addr(_ip.c_str());
       local.sin_addr.s_addr =INADDR_ANY ;
       // 或者直接输入0；可以理解成匹配同一主机的不同ip（多个网卡）的任意des-port相同的不同进程发来的信息
        int n = bind(_socketfd, (sockaddr *)&local, sizeof(local));//程序终止bind的网络信息自动解除
        if (n < 0)
            use_log(loglevel::DEBUG) << "bind failure!";
        use_log(loglevel::DEBUG) << "bind success!";
    }

    void start()
    {

        // 服务器用不挂掉->死循环：
        _isrunning = 1;
        while (_isrunning)
        {
            char buff[1024] = {0};
            sockaddr_in per;
            socklen_t len = sizeof(per);                                                          // 套接字长度就是字节数
            ssize_t rm = recvfrom(_socketfd, buff, sizeof(buff) - 1, 0, (sockaddr *)&per, &len); // 输出型参数故取地址

            if (rm< 0) use_log(loglevel::DEBUG) << "recvfrom failure!";
              buff[rm]=0;

              string per_addr= inet_ntoa(per.sin_addr);
              uint16_t per_port=ntohs(per.sin_port);
               cout<< "$client :[addr: "<<per_addr<<" port: "<<per_port<<" ] say: "<<buff<<endl;
               //string res="server say:";
              // res+=buff;
            //int  so=sendto(_socketfd,res.c_str(),res.size(),0,(sockaddr *)&per,len);//这里接收两个全都对套接字用的是指针：继承多态效果
               //回调函数，最后传给client
           string ans= _func(buff,per);
            int  so=sendto(_socketfd,ans.c_str(),ans.size(),0,(sockaddr *)&per,len);//这里接收两个全都对套接字用的是指针：继承多态效果

           //输入型参数
           if (so < 0) use_log(loglevel::DEBUG) << "sendto failure!";
        }
    }

    ~udpserver()
    {
    }

private:
    //string _ip;
    uint16_t _port;
    int _socketfd;
    bool _isrunning;
    func_t _func;
};